/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package nonequidistant.FEMSolver1D;

import Integration.IFunction1D;
import MathLib.HashMatrix.Gauss;
import MathLib.HashMatrix.HashMatrix;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import nonequidistant.FEMShapeFunctions1D.FEMShapeFunction1D1Pow;
import syntaxanalyser.PostfiksX;

/**
 *
 * @author mark_o
 */
public class StatMainMatrixGenerator {
    HashMatrix A;
    double[] b;
    ArrayList<Double> NodeList;
    ArrayList<FEMShapeFunction1D1Pow> FuncList;

    String pString="1";
    String wString="0";
    String qString="10";
    String fString="100";

    double left;
    double right;

    boolean DirihetA;
    double AVal;
    boolean DirihetB;
    double BVal;


    public StatMainMatrixGenerator(ArrayList<Double> NodeList) {
        this.NodeList = NodeList;
        A = new HashMatrix(HashMatrix.ARRAY_TYPE, NodeList.size());
        b = new double[NodeList.size()];
        generateFunctions();

    }

    private void generateFunctions(){
        FuncList = new ArrayList<FEMShapeFunction1D1Pow>();
        FuncList.add(new FEMShapeFunction1D1Pow(NodeList.get(0), 0.0,NodeList.get(1) - NodeList.get(0)));
        for (int i = 1; i < NodeList.size()-1; i++) {
            double h1 = NodeList.get(i) - NodeList.get(i-1);
            double h2 = NodeList.get(i+1) - NodeList.get(i);
            FuncList.add(new FEMShapeFunction1D1Pow(NodeList.get(i), h1,h2));
        }
        int n = NodeList.size()-1;
        FuncList.add(new FEMShapeFunction1D1Pow(NodeList.get(n), NodeList.get(n) - NodeList.get(n-1), 0.0));
    }

    public void Generate() {
//        StatMatrixGenerator gen = new StatMatrixGenerator(NodeList.get(0),NodeList.get(NodeList.size()-1));
        StatMatrixGenerator gen = new StatMatrixGenerator();

        gen.setLeft(left);
        gen.setRight(right);

        IFunction1D p = new IFunction1D() {

            public double calculate(double x) {
                try {
                    return PostfiksX.Calculate(pString, x);
                } catch (Exception ex) {
                    Logger.getLogger(StatMainMatrixGenerator.class.getName()).log(Level.SEVERE, null, ex);
                }
                return 0;
            }

            public double calculateDerivaty(double x) {
                throw new UnsupportedOperationException("Not supported yet.");
            }
        };
        IFunction1D w = new IFunction1D() {

            public double calculate(double x) {
                try {
                    return PostfiksX.Calculate(wString, x);
                } catch (Exception ex) {
                    Logger.getLogger(StatMainMatrixGenerator.class.getName()).log(Level.SEVERE, null, ex);
                }
                return 0;
            }

            public double calculateDerivaty(double x) {
                throw new UnsupportedOperationException("Not supported yet.");
            }
        };
        IFunction1D q = new IFunction1D() {

            public double calculate(double x) {
                try {
                    return PostfiksX.Calculate(qString, x);
                } catch (Exception ex) {
                    Logger.getLogger(StatMainMatrixGenerator.class.getName()).log(Level.SEVERE, null, ex);
                }
                return 0;
            }

            public double calculateDerivaty(double x) {
                throw new UnsupportedOperationException("Not supported yet.");
            }
        };
        IFunction1D f = new IFunction1D() {

            public double calculate(double x) {
                try {
                    return PostfiksX.Calculate(fString, x);
                } catch (Exception ex) {
                    Logger.getLogger(StatMainMatrixGenerator.class.getName()).log(Level.SEVERE, null, ex);
                }
                return 0;
            }

            public double calculateDerivaty(double x) {
                throw new UnsupportedOperationException("Not supported yet.");
            }
        };

        
            gen.setF1(FuncList.get(0));
            gen.setF2(FuncList.get(1));
            double[][] tmp = gen.getAll(p, q, w);
            double[] tmpb = gen.getFe(f);

//            tmp = gen.getAll(p, q, w);
//
//            A.setValue(0, 0, A.getValue(0, 0) + tmp[0][0]);
//            A.setValue(0, 1, A.getValue(0, 1) + tmp[0][1]);
//            A.setValue(1, 0, A.getValue(1, 0) + tmp[1][0]);
//            A.setValue(1, 1, A.getValue(1, 1) + tmp[1][1]);
//            b[0]+=tmpb[0];
//            b[1]+=tmpb[1];

        for (int i = 0; i < b.length-1; i++) {
            //IFunction1D f1 = FuncList.get(i);
            gen.setF1(FuncList.get(i));
            //gen.setF2(FuncList.get(i));
            //A.setValue(i, i, gen.getKe(p)+gen.getAdv(w)+gen.getMe(q));
//            for (int j = 0; j < b.length; j++) {
//                gen.setF2(FuncList.get(j));
//                double val = gen.getKe(p)+gen.getAdv(w)+gen.getMe(q);
//                A.setValue(i, j, val);
//            }
//            gen.setF2(FuncList.get(i-1));
//            tmp = gen.getAll(p, q, w);
//            tmpb = gen.getFe(f);
//
//            A.setValue(i-1, i-1, A.getValue(i-1, i-1) + tmp[0][0]);
//            A.setValue(i-1, i, A.getValue(i-1, i) + tmp[0][1]);
//            A.setValue(i, i-1, A.getValue(i, i-1) + tmp[1][0]);
//            A.setValue(i, i, A.getValue(i, i) + tmp[1][1]);
//            b[i-1]+=tmpb[0];
//            b[i]+=tmpb[1];

            gen.setF2(FuncList.get(i+1));
            tmp = gen.getAll(p, q, w);
            tmpb = gen.getFe(f);

            A.setValue(i, i, A.getValue(i, i) + tmp[0][0]);
            A.setValue(i, i+1, A.getValue(i, i+1) + tmp[0][1]);
            A.setValue(i+1, i, A.getValue(i+1, i) + tmp[1][0]);
            A.setValue(i+1, i+1, A.getValue(i+1, i+1) + tmp[1][1]);
            b[i]+=tmpb[0];
            b[i+1]+=tmpb[1];
        }

//            int n = b.length-1;
//            gen.setF1(FuncList.get(n-1));
//            gen.setF2(FuncList.get(n));
//            tmp = gen.getAll(p, q, w);
//            tmpb = gen.getFe(f);
//
//            A.setValue(i, i, A.getValue(i, i) + tmp[0][0]);
//            A.setValue(i, i+1, A.getValue(i, i+1) + tmp[0][1]);
//            A.setValue(i+1, i, A.getValue(i+1, i) + tmp[1][0]);
//            A.setValue(i+1, i+1, A.getValue(i+1, i+1) + tmp[1][1]);
//            b[i]+=tmpb[0];
//            b[i+1]+=tmpb[1];

        for (int i = 0; i < b.length; i++) {
            for (int j = 0; j < b.length; j++) {
                System.out.print(A.getValue(i, j)+"\t");
            }
            System.out.println("\t"+b[i]);
        }

    }

    public void applyBounderiesForCoupling(){
        if (DirihetA) {
            b[0] = AVal;
            b[1]-= AVal*A.getValue(1, 0);
            A.setValue(0, 0, 1);
            A.setValue(0, 1, 0);
            A.setValue(1, 0, 0);
        }else{
            b[0]+=AVal;
        }


        //Dirihlet b:
        if (DirihetB) {
            b[b.length-1] = BVal;
            b[b.length-2]-= BVal*A.getValue(b.length-2, b.length-1);
            A.setValue(A.getN()-1, A.getN()-1, 1);
            A.setValue(A.getN()-1, A.getN()-2, 0);
            A.setValue(A.getN()-2, A.getN()-1, 0);
        }else{
            b[b.length-1]+=BVal;
        }
    }


    public double[] Solve(String outPath){
        //LUFactorization lu = new LUFactorization(A);
        Gauss lu = new Gauss(A);

        //Neyman a:
        //b[0]+=1;

        //Dirihlet a:
        if (DirihetA) {
            b[0] = AVal;
            b[1]-= AVal*A.getValue(1, 0);
            A.setValue(0, 0, 1);
            A.setValue(0, 1, 0);
            A.setValue(1, 0, 0);
        }else{
            b[0]+=AVal;
        }


        //Dirihlet b:
        if (DirihetB) {
            b[b.length-1] = BVal;
            b[b.length-2]-= BVal*A.getValue(b.length-2, b.length-1);
            A.setValue(A.getN()-1, A.getN()-1, 1);
            A.setValue(A.getN()-1, A.getN()-2, 0);
            A.setValue(A.getN()-2, A.getN()-1, 0);
        }else{
            b[b.length-1]+=BVal;
        }

        double[] res = lu.calculate(b);
        for (int j = 0; j < b.length; j++) {
            System.out.println(NodeList.get(j)+"\t"+res[j]);
        }
        return res;
    }

    public ArrayList<Double> generateBFEM(boolean left){
        MatrixGenerator1 gen = new MatrixGenerator1(NodeList.get(0),NodeList.get(NodeList.size()-1));

//        gen.setLeft(this.left-NodeList.get(1)+NodeList.get(0));
//        gen.setRight(this.right+NodeList.get(1)-NodeList.get(0));
        gen.setLeft(this.left);
        gen.setRight(this.right);
        if(left){
            gen.setF1(FuncList.get(0));
        }else{
            gen.setF1(FuncList.get(FuncList.size()-1));
        }

        ArrayList<Double> res = new ArrayList<Double>();
        IFunction1D constF = new IFunction1D() {

            public double calculate(double x) {
                return 1.0;
            }

            public double calculateDerivaty(double x) {
                return 0.0;
            }
        };
        for (int i = 0; i < FuncList.size(); i++) {
            gen.setF2(FuncList.get(i));
            res.add(gen.getMe(constF));
        }

        return res;
    }

    public ArrayList<Double> generateBFEMPox(boolean left){
        MatrixGenerator1 gen = new MatrixGenerator1(NodeList.get(0),NodeList.get(NodeList.size()-1));

        gen.setLeft(this.left-NodeList.get(1)+NodeList.get(0));
        gen.setRight(this.right+NodeList.get(1)-NodeList.get(0));
        if(left){
            gen.setF1(FuncList.get(0));
        }else{
            gen.setF1(FuncList.get(FuncList.size()-1));
        }

        ArrayList<Double> res = new ArrayList<Double>();
        IFunction1D constF = new IFunction1D() {

            public double calculate(double x) {
                return 1.0;
            }

            public double calculateDerivaty(double x) {
                return 0.0;
            }
        };
        for (int i = 0; i < FuncList.size(); i++) {
            gen.setF2(FuncList.get(i));
            res.add(gen.getAdv(constF));
        }

        return res;
    }

    public HashMatrix getA() {
        return A;
    }

    public double[] getB() {
        return b;
    }

    public void setAVal(double AVal) {
        this.AVal = AVal;
    }

    public void setBVal(double BVal) {
        this.BVal = BVal;
    }

    public void setDirihetA(boolean DirihetA) {
        this.DirihetA = DirihetA;
    }

    public void setDirihetB(boolean DirihetB) {
        this.DirihetB = DirihetB;
    }

    public void setfString(String fString) {
        this.fString = fString;
    }

    public void setpString(String pString) {
        this.pString = pString;
    }

    public void setqString(String qString) {
        this.qString = qString;
    }

    public void setwString(String wString) {
        this.wString = wString;
    }

    public void setLeft(double left) {
        this.left = left;
    }

    public void setRight(double right) {
        this.right = right;
    }

    public static void main(String[] args){
        ArrayList<Double> list = new ArrayList<Double>();
        double a = 0.0;
        double b = 1.0;

//        int N = 50;
//        double h = (b-a)/N;
//        for (int i = 0; i <= N; i++) {
//            list.add(a+h*i);
//        }
//        a = 0.0;
//        b = 0.5;
//        int N = 20;
//        double h = (b-a)/N;
//        for (int i = 0; i <=N; i++) {
//            list.add(a+h*i);
//        }
//
//        a = 0.5;
//        b = 0.8;
//        N = 30;
//        h = (b-a)/N;
//        for (int i = 1; i <= N; i++) {
//            list.add(a+h*i);
//        }
//
//        a = 0.8;
//        b = 1.0;
//        N = 40;
//        h = (b-a)/N;
//        for (int i = 1; i <= N; i++) {
//            list.add(a+h*i);
//        }
//        a=0.0;
//        b=1.0;

                list.add( 0.0);
list.add(
   0.111111111111111
);
list.add(
   0.138888888888889
);
list.add(
   0.166666666666667
);
list.add(
   0.222222222222222

);
list.add(
   0.277777777777778

);
list.add(
   0.333333333333333

);
list.add(
   0.361111111111111

);
list.add(
   0.388888888888889

);
list.add(
   0.416666666666667

);
list.add(
   0.444444444444444

);
list.add(
   0.472222222222222

);
list.add(
   0.500000000000000

);
list.add(
   0.527777777777778

);
list.add(
   0.555555555555556

);
list.add(
   0.583333333333333

);
list.add(
   0.611111111111111

);
list.add(
   0.638888888888889

);
list.add(
   0.666666666666667

);
list.add(
   0.694444444444444

);
list.add(
   0.722222222222222

);
list.add(
   0.750000000000000

);
list.add(
   0.777777777777778

);
list.add(
   0.805555555555555

);
list.add(
   0.819444444444444

);
list.add(
   0.826388888888889

);
list.add(
   0.833333333333333

);
list.add(
   0.836805555555555

);
list.add(
   0.840277777777778

);
list.add(
   0.843750000000000

);
list.add(
   0.847222222222222

);
list.add(
   0.848958333333333

);
list.add(
   0.850694444444444

);
list.add(
   0.852430555555555

);
list.add(
   0.854166666666667

);
list.add(
   0.855902777777778

);
list.add(
   0.856770833333333

);
list.add(
   0.857638888888889

);
list.add(
   0.858506944444444

);
list.add(
   0.859375000000000

);
list.add(
   0.860243055555556

);
list.add(
   0.861111111111111

);
list.add(
   0.861328125000000

);
list.add(
   0.861545138888889

);
list.add(
   0.861979166666667

);
list.add(
   0.862847222222222

);
list.add(
   0.864583333333333

);
list.add(
   0.868055555555556

);
list.add(
   0.871527777777778

);
list.add(
   0.875000000000000

);
list.add(
   0.876736111111111

);
list.add(
   0.878472222222222

);
list.add(
   0.881944444444444

);
list.add(
   0.883680555555556

);
list.add(
   0.885416666666667

);
list.add(
   0.887152777777778

);
list.add(
   0.888888888888889

);
list.add(
   0.889756944444444

);
list.add(
   0.890625000000000

);
list.add(
   0.892361111111111

);
list.add(
   0.895833333333333

);
list.add(
   0.899305555555555

);
list.add(
   0.901041666666667

);
list.add(
   0.902777777777778

);
list.add(
   0.904513888888889

);
list.add(
   0.906250000000000

);
list.add(
   0.907986111111111

);
list.add(
   0.909722222222222

);
list.add(
   0.911458333333333

);
list.add(
   0.912326388888889

);
list.add(
   0.913194444444444

);
list.add(
   0.914062500000000

);
list.add(
   0.914930555555556

);
list.add(
   0.915798611111111

);
list.add(
   0.916666666666667

);
list.add(
   0.916883680555556

);
list.add(
   0.917100694444444

);
list.add(
   0.917534722222222

);
list.add(
   0.918402777777778

);
list.add(
   0.920138888888889

);
list.add(
   0.923611111111111

);
list.add(
   0.927083333333333

);
list.add(
   0.930555555555556

);
list.add(
   0.932291666666667

);
list.add(
   0.934027777777778

);
list.add(
   0.935763888888889

);
list.add(
   0.937500000000000

);
list.add(
   0.939236111111111

);
list.add(
   0.940972222222222

);
list.add(
   0.942708333333333

);
list.add(
   0.944444444444444

);
list.add(
   0.944878472222222

);
list.add(
   0.945312500000000

);
list.add(
   0.946180555555556

);
list.add(
   0.947916666666667

);
list.add(
   0.949652777777778

);
list.add(
   0.951388888888889

);
list.add(
   0.953125000000000

);
list.add(
   0.954861111111111

);
list.add(
   0.955729166666667

);
list.add(
   0.956597222222222

);
list.add(
   0.957465277777778

);
list.add(
   0.958333333333333

);
list.add(
   0.958767361111111

);
list.add(
   0.959201388888889

);
list.add(
   0.960069444444444

);
list.add(
   0.961805555555555

);
list.add(
   0.963541666666667

);
list.add(
   0.965277777777778

);
list.add(
   0.967013888888889

);
list.add(
   0.968750000000000

);
list.add(
   0.969618055555556

);
list.add(
   0.970486111111111

);
list.add(
   0.971354166666667

);
list.add(
   0.972222222222222

);
list.add(
   0.972656250000000

);
list.add(
   0.973090277777778

);
list.add(
   0.973958333333333

);
list.add(
   0.975694444444444

);
list.add(
   0.979166666666667

);
list.add(
   0.980902777777778

);
list.add(
   0.982638888888889

);
list.add(
   0.984375000000000

);
list.add(
   0.986111111111111

);
list.add(
   0.987847222222222

);
list.add(
   0.989583333333333

);
list.add(
   0.991319444444444

);
list.add(
   0.992187500000000

);
list.add(
   0.993055555555556

);
list.add(
   0.993923611111111

);
list.add(
   0.994791666666667

);
list.add(
   0.995659722222222

);
list.add(
   0.996527777777778

);
list.add(
   0.997395833333333

);
list.add(
   0.998263888888889

);
list.add(
   0.999131944444444

);
list.add(
     1.0
);



        StatMainMatrixGenerator gen = new StatMainMatrixGenerator(list);

        gen.setLeft(a);
            gen.setRight(b);
            gen.setfString("100");
            gen.setwString("100");
            gen.setqString("0");
            gen.setpString("1");
            gen.setDirihetB(true);
            gen.setBVal(0.0);
            gen.setDirihetA(true);
            gen.setAVal(0.0);

        gen.Generate();
        gen.Solve("");
    }
}
